using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using Medianamik.Core.Caching;
using Medianamik.Core.DAL;
using Medianamik.Core.Interfaces;
using Medianamik.Tests.Unit.Logic;
using Moq;
using Moq.Language.Flow;
using NUnit.Framework;
using Medianamik.UI.Web.ModalWindows;
using Medianamik.Core;

namespace Medianamik.Tests.Unit.Medianamik.UI.Web.ModalWindows
{
    [TestFixture]
    public class DeleteNodeWindowTest
    {
        [Test]
        public void We_should_be_able_to_delete_a_node_even_if_it_contains_only_one_instance()
        {
            var nodeToDelete = CreateNodeWithInstancesFromCultureNames("fr-CA");
            var deleteOptions = new DropDownList { Visible = false };
            var deleteWindow = new DeleteNodeWindowFake(deleteOptions, nodeToDelete);

            var nodeProvider = new Mock<INodeDALProvider>();
            EnsureThatNodeDoesNotHaveAnyChild(nodeProvider);

            deleteWindow.DeleteNode(new Object(), EventArgs.Empty);

            nodeProvider.Verify(d =>
                                d.TransacSave(It.IsAny<IEnumerable<NodeDataShell>>()), Times.Once());

            Assert.That(nodeToDelete.Status, Is.EqualTo(EntityStates.Deleted));
            Assert.That(deleteWindow.MessageDisplayed, Is.EqualTo(DeleteNodeWindowFake.DeleteMessage));
        }

        [Test]
        public void We_should_be_able_to_destroy_a_node_even_if_it_contains_only_one_instance()
        {
            var deleteOptions = new DropDownList { Visible = false };
            var nodeToDelete = CreateNodeWithInstancesFromCultureNames("fr-CA");
            var deleteWindow = new DeleteNodeWindowFake(deleteOptions, nodeToDelete);
            deleteWindow.NodeIsDestroyable(true);

            var nodeProvider = new Mock<INodeDALProvider>();
            EnsureThatNodeDoesNotHaveAnyChild(nodeProvider);

            deleteWindow.DeleteNode(new Object(), EventArgs.Empty);

            nodeProvider.Verify(d =>
                                d.DeleteNode(nodeToDelete.ID, true), Times.Once());

            Assert.That(deleteWindow.MessageDisplayed, Is.EqualTo(DeleteNodeWindowFake.DeleteMessage));
        }

        [Test]
        public void We_should_be_able_to_destroy_a_branch_that_contains_one_instance()
        {
            var nodes = CreateNodeHierarchyFromCultureNames("fr-CA");

            var rootNode = nodes.First();
            var childNode = nodes.Last();

            var deleteOptions = new DropDownList { Visible = false };
            var deleteWindow = new DeleteNodeWindowFake(deleteOptions, rootNode);
            deleteWindow.NodeIsDestroyable(true);

            var nodeProvider = new Mock<INodeDALProvider>();
            EnsureThatNodeDoesNotHaveAnyChild(nodeProvider);

            deleteWindow.DeleteNode(new Object(), EventArgs.Empty);

            nodeProvider.Verify(d =>
                                d.DeleteNode(rootNode.ID, true), Times.Once());

            nodeProvider.Verify(d =>
                                d.DeleteNode(childNode.ID, true), Times.Once());

            Assert.That(deleteWindow.MessageDisplayed, Is.EqualTo(DeleteNodeWindowFake.DeleteMessage));
        }

        private IEnumerable<Node> CreateNodeHierarchyFromCultureNames(params string[] cultureNames)
        {
            var rootNode = new Node();
            rootNode.Path = String.Format(".{0}.", rootNode.ID);
            rootNode.ChildNodeCount = 1;

            var childNode = new Node();
            childNode.ParentID = rootNode.ID;
            childNode.Path = String.Format("{0}{1}.", rootNode.Path, childNode.ID);

            cultureNames.ForEach(c =>
                                     {
                                         rootNode.InternalInstances.Add(new NodeInstance(rootNode, c));
                                         childNode.InternalInstances.Add(new NodeInstance(childNode, c));
                                     });

            var cacheProvider = new Mock<INodeCacheProvider>();

            cacheProvider.Setup(x => x.GetNodes(It.IsAny<IQueryDefinition>(), It.IsAny<bool>()))
                .ReturnsInOrder(new[] { rootNode }, new[] { childNode });

            NodeManager.CacheProvider = cacheProvider.Object;

            return new[] { rootNode, childNode };
        }

        private Node CreateNodeWithInstancesFromCultureNames(params string[] cultureNames)
        {
            var node = new Node();

            cultureNames.ForEach(c => node.InternalInstances.Add(new NodeInstance(node, c)));

            CreateExistingNodes(new[] { node });

            return node;
        }

        private void EnsureThatNodeDoesNotHaveAnyChild(Mock<INodeDALProvider> nodeProvider)
        {
            var dalProvider = new Mock<IDALProvider>();

            dalProvider.Setup(dal => dal.NodeDALProvider).Returns(nodeProvider.Object);

            nodeProvider.Setup(d => d.ChildNodeCount(It.IsAny<Guid[]>()))
                .Returns(new Dictionary<Guid, int> { { Guid.Empty, 0 } });

            DALProviderManager.DALProvider = dalProvider.Object;
        }

        private void CreateExistingNodes(IEnumerable<Node> expectedNodes)
        {
            var cacheProvider = new Mock<INodeCacheProvider>();

            cacheProvider.Setup(x => x.GetNodes(It.IsAny<IQueryDefinition>(), It.IsAny<bool>()))
                .Returns(expectedNodes);

            cacheProvider.Setup(x => x.GetNodeCount(It.IsAny<IQueryDefinition>()))
                .Returns(expectedNodes.Count);

            NodeManager.CacheProvider = cacheProvider.Object;
        }
    }

    public class DeleteNodeWindowFake : DeleteNodeWindow
    {
        public const string DeleteMessage = "Delete";
        private Node _node;

        protected override Node Node
        {
            get
            {
                return _node;
            }
        }
        public DeleteNodeWindowFake(DropDownList deleteOptions, Node node)
        {
            _deleteOptionsAccessor = deleteOptions;
            _node = node;
            NodeIsDestroyable(false);
        }

        protected override Guid? NodeId
        {
            get { return Node.ID; }
        }

        private string _cultureName;
        protected override string CultureName
        {
            get { return _cultureName; }
        }

        DropDownList _deleteOptionsAccessor;
        protected override DropDownList deleteOptionsAccessor
        {
            get { return _deleteOptionsAccessor; }
        }

        private bool _destroy;
        protected override bool Destroy
        {
            get { return _destroy; }
        }

        protected override string GetMessageToDisplayWhenDeleteAccomplished()
        {
            return DeleteMessage;
        }

        public string MessageDisplayed { get; set; }

        protected override void DisplayMessage(string message)
        {
            MessageDisplayed = message;
        }

        public void SetNodeInstanceCultureName(string cultureName)
        {
            _cultureName = cultureName;
        }

        public void NodeIsDestroyable(bool destroyable)
        {
            _destroy = destroyable;
        }
    }
}